
#ifndef Helper_h
#define Helper_h
#include "cJSON.h"
#include "esp_log.h"
#include "esp_mac.h"
#include <stdio.h>
#include <string.h>
class Helper {
public:
	/// @brief Returns the total amount of bytes needed to store the formatted
	/// string that will be created if the given format string and the arguments
	/// are passed to snprintf.
	/// @tparam ...Args Holds the multiple arguments that will simply be
	/// forwarded to the snprintf method, allowing any arbitrary amount of
	/// combinations without having to rely on va_list
	/// @param format Formatting message that the given arguments will be
	/// inserted into
	/// @param ...args Arguments that will be forwarded into the snprintf method
	/// see https://cplusplus.com/reference/cstdio/snprintf/ for more
	/// information
	/// @return Amount of bytes in characters, needed for the formatted string
	/// with the given arguments inserted, to be displayed completly
	template <typename... Args>
	static int detectSize(char const *format, Args const &...args) {
		// 结果（Result）表示如果传入的缓冲区足够大（不包括末尾的空字符），本应该写入的字符数；
		// 如果在创建字符串时发生错误，则返回一个负数。
		// 为了在根据这个结果创建数组时不会因为负数大小导致系统崩溃，
		// 我们会提前用断言（assert）进行检查，并给出清晰的错误提示。
		const int result = snprintf(nullptr, 0U, format, args...) + 1U;
		assert(result >= 0);
		return result;
	}

	static bool mqttTopicMatchPlus(const char *pattern, const char *topic) {
		const char *p = pattern;
		const char *t = topic;

		while (*p && *t) {
			if (*p == '+') {
				// '+' 只能匹配到下一个 '/'
				while (*t && *t != '/') {
					t++;
				}
				p++; // 跳过 '+'
			} else if (*p == *t) {
				p++;
				t++;
			} else {
				return false; // 不匹配
			}
		}

		// 允许 pattern 在末尾是 '+' 且 topic 没有多余字符
		if (*p == '+' && *(p + 1) == '\0') {
			return strchr(t, '/') == NULL;
		}

		// 两个都到末尾才算匹配
		return *p == '\0' && *t == '\0';
	}

	// 生成设备ID (IMEI-like, 基于MAC地址)
	static void generateDeviceId(char out[16]) {
		uint8_t mac[6];
		esp_err_t ret = esp_read_mac(mac, ESP_MAC_WIFI_STA);

		if (ret != ESP_OK) {
			strncpy(out, "860000000000000", 16);
			out[15] = '\0'; // 确保null终止
			return;
		}

		// 使用合理的TAC
		const char *tac = "163020"; // 6位TAC

		// 从MAC生成8位序列号
		uint32_t serial_num = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
		serial_num = serial_num % 100000000; // 确保8位数字

		// 前14位 - 使用更大的缓冲区防止溢出
		char base_imei[20];
		int written = snprintf(base_imei, sizeof(base_imei), "%s%08lu", tac, serial_num);

		if (written < 0 || written >= (int)sizeof(base_imei)) {
			ESP_LOGE("", "snprintf failed or truncated: %d", written);
			out[15] = '\0';
			return;
		}

		// 确保base_imei正好是14位数字
		if (strlen(base_imei) != 14) {
			strncpy(out, "860000000000000", 16);
			out[15] = '\0';
			return;
		}

		// 计算校验位 - 使用正确的Luhn算法
		int sum = 0;
		for (int i = 0; i < 14; i++) {
			// 验证字符是数字
			if (base_imei[i] < '0' || base_imei[i] > '9') {
				strncpy(out, "860000000000000", 16);
				out[15] = '\0';
				return;
			}

			int digit = base_imei[i] - '0';
			// Luhn算法：从右向左，偶数位（从1开始计数）乘2
			// 因为我们从左向右处理，所以索引为偶数的位置实际上是奇数位（从1开始）
			if (i % 2 == 0) { // 索引0,2,4,...对应位置1,3,5,...
				digit *= 2;
				if (digit > 9) {
					digit -= 9;
				}
			}
			sum += digit;
		}

		int check_digit = (10 - (sum % 10)) % 10;

		// 生成最终IMEI
		written = snprintf(out, 16, "%s%d", base_imei, check_digit);

		if (written != 15) {
			strncpy(out, "860000000000000", 16);
			out[15] = '\0';
		}
	}

	static void copy_cjson_string(char *dest, size_t dest_size, cJSON *basic,
								  const char *field) {
		cJSON *item = cJSON_GetObjectItem(basic, field);
		if (item && cJSON_IsString(item) && item->valuestring) {
			strncpy(dest, item->valuestring, dest_size - 1);
			dest[dest_size - 1] = '\0';
		} else {
			if (dest_size > 0) {
				dest[0] = '\0'; // 为空时清空目标字符串
			}
		}
	}

	static void copy_cjson_bool(bool *dest, cJSON *data, const char *field) {
		cJSON *item = cJSON_GetObjectItem(data, field);
		if (item && cJSON_IsBool(item)) {
			*dest = item->valueint;
		}
	}

	static void copy_cjson_number(int *dest, cJSON *data, const char *field) {
		cJSON *item = cJSON_GetObjectItem(data, field);
		if (item && cJSON_IsNumber(item)) {
			*dest = item->valueint;
		}
	}
};

#endif // Helper
